from datetime import datetime, date
from flask import current_app  # 关键：添加current_app导入
from flask_login import UserMixin
from flask_sqlalchemy import SQLAlchemy
import os  # 关键：添加os模块导入
import pytz
import hashlib
from werkzeug.security import generate_password_hash, check_password_hash

BEIJING_TZ = pytz.timezone('Asia/Shanghai')
db = SQLAlchemy()


# ======================
# 收藏关联模型
# ======================
class Favorite(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
    problem_id = db.Column(db.Integer, db.ForeignKey('problem.id'), nullable=False)
    created_at = db.Column(db.DateTime, default=lambda: datetime.now(BEIJING_TZ))
    user = db.relationship('User', backref=db.backref('favorites', lazy=True))
    problem = db.relationship('Problem', backref=db.backref('favorited_by', lazy=True))


# ======================
# 用户模型
# ======================
class User(db.Model, UserMixin):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True, nullable=False)
    solved_problems = db.relationship('Problem', secondary='user_solved', backref='solved_by')
    submissions = db.relationship('Submission', backref='user', lazy=True)
    comments = db.relationship('Comment', backref='user', lazy=True)
    email = db.Column(db.String(120), unique=True, nullable=True)
    password_hash = db.Column(db.String(128), nullable=False)  # 存储加密后的密码
    avatar = db.Column(db.String(128), nullable=True)  # 头像文件名
    is_superuser = db.Column(db.Boolean, default=False)  # 超级管理员标识
    is_disabled = db.Column(db.Boolean, default=False, nullable=False)  # 账号禁用
    is_deleted = db.Column(db.Boolean, default=False, nullable=False)  # 账号注销
    notifications = db.relationship('Notification', backref='recipient', lazy=True, cascade="all, delete-orphan")

    def set_password(self, password):
        """设置密码（自动哈希）"""
        self.password_hash = generate_password_hash(password)

    @property
    def password(self):
        raise AttributeError('password is not a readable attribute')

    @password.setter
    def password(self, password):
        self.password_hash = generate_password_hash(password)

    def verify_password(self, password):
        return check_password_hash(self.password_hash, password)

    def get_avatar_url(self, size=100):
        """生成头像URL（优先上传头像 → Gravatar → 默认首字母）"""
        if self.avatar:
            return f"/static/uploads/avatars/{self.avatar}"
        if self.email:
            hash = hashlib.md5(self.email.lower().encode('utf-8')).hexdigest()
            return f"https://www.gravatar.com/avatar/{hash}?s={size}&d=identicon"
        initial = self.username[0].upper() if self.username else "?"
        return f"data:image/svg+xml;charset=UTF-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='{size}' height='{size}' viewBox='0 0 100 100'%3E%3Crect width='100' height='100' fill='%234a90e2'/%3E%3Ctext x='50' y='60' font-family='Arial' font-size='40' text-anchor='middle' fill='white'%3E{initial}%3C/text%3E%3C/svg%3E"


# ======================
# 打卡记录模型
# ======================
class ClockInRecord(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
    date = db.Column(db.Date, nullable=False, default=date.today)
    user = db.relationship('User', backref=db.backref('clock_in_records', lazy=True))

# ======================
# 题目模型（核心，关联测试用例和模板）
# ======================
class Problem(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(100), nullable=False)
    description = db.Column(db.Text, nullable=False)
    template_file = db.Column(db.String(255), nullable=False)
    testcases_dir = db.Column(db.String(255), nullable=False)
    difficulty = db.Column(db.String(20), nullable=False)
    initial_codes = db.Column(db.JSON, default={})       # 初始代码（{语言: 代码}）
    function_signature = db.Column(db.JSON, default={})  # 函数签名（JSON）
    output_type = db.Column(db.String(20), default="ordered")  # 输出类型
    submissions = db.relationship('Submission', backref='problem', lazy=True)
    cpp_template_path = db.Column(db.String(255))  # 新增：存储 .cpp 模板文件路径

    def get_sample_test_case(self):
        """获取一个示例测试用例用于展示"""
        from judge.judge import Judge
        test_cases = Judge()._load_test_cases_from_files(self.testcases_dir)
        return test_cases[0] if test_cases else None
    
    @property
    def testcases_count(self):
        if not self.testcases_dir:
            return 0
        
        # 跳转到项目根目录（OnlineJudge/），而非 web/
        project_root = os.path.dirname(current_app.root_path)  
        testcases_abs_path = os.path.join(project_root, self.testcases_dir)
        
        if not os.path.isdir(testcases_abs_path):
            print(f"[ERROR] 目录不存在: {testcases_abs_path}")
            return 0
        
        try:
            in_files = [f for f in os.listdir(testcases_abs_path) if f.lower().endswith(".in")]
            return len(in_files)
        except OSError as e:
            current_app.logger.error(f"读取测试用例目录失败: {e}", exc_info=True)
            return 0

    @property
    def has_template(self):
        if not self.template_file:
            return False
        
        # 跳转到项目根目录（OnlineJudge/），而非 web/
        project_root = os.path.dirname(current_app.root_path)  
        template_abs_path = os.path.join(project_root, "code_templates", self.template_file)
        
        if not os.path.exists(template_abs_path):
            print(f"[ERROR] 文件不存在: {template_abs_path}")
            return False
        return True

# ======================
# 帖子点赞模型
# ======================
class PostLike(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
    post_id = db.Column(db.Integer, db.ForeignKey('forum_post.id'), nullable=False)
    created_at = db.Column(db.DateTime, default=datetime.utcnow)
    __table_args__ = (db.UniqueConstraint('user_id', 'post_id', name='unique_user_post_like'),)


# ======================
# 论坛帖子模型
# ======================
class ForumPost(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(200), nullable=False)
    content = db.Column(db.Text, nullable=False)
    created_at = db.Column(db.DateTime, default=lambda: datetime.now(BEIJING_TZ))
    updated_at = db.Column(db.DateTime, default=lambda: datetime.now(BEIJING_TZ), onupdate=lambda: datetime.now(BEIJING_TZ))
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
    author = db.relationship('User', backref=db.backref('forum_posts', lazy=True))
    comments = db.relationship('ForumComment', backref='post', lazy=True, cascade="all, delete-orphan")
    likes = db.relationship('PostLike', backref='post', lazy=True, cascade='all, delete-orphan')
    # 新增置顶字段
    is_pinned = db.Column(db.Boolean, default=False, nullable=False)
    # 新增：审核状态（默认未审核）
    is_approved = db.Column(db.Boolean, default=False, nullable=False)

    #user = db.relationship('User', backref=db.backref('posts', lazy=True))
    
# ======================
# 论坛评论模型（支持多层回复）
# ======================
class ForumComment(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    content = db.Column(db.Text, nullable=False)
    created_at = db.Column(db.DateTime, default=lambda: datetime.now(BEIJING_TZ))
    post_id = db.Column(db.Integer, db.ForeignKey('forum_post.id', ondelete='CASCADE'), nullable=False)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
    parent_id = db.Column(db.Integer, db.ForeignKey('forum_comment.id', ondelete='CASCADE'), nullable=True)
    author = db.relationship('User', backref=db.backref('forum_comments', lazy=True))
    replies = db.relationship('ForumComment', backref=db.backref('parent', remote_side=[id]), lazy=True, cascade="all, delete-orphan")

# 新增：通知模型
class Notification(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    content = db.Column(db.String(500), nullable=False)  # 通知内容
    is_read = db.Column(db.Boolean, default=False)  # 是否已读
    created_at = db.Column(db.DateTime, default=datetime.utcnow)  # 通知时间
    recipient_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)  # 接收者ID
    
# ======================
# 提交记录模型
# ======================
class Submission(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
    problem_id = db.Column(db.Integer, db.ForeignKey('problem.id'), nullable=False)
    code = db.Column(db.Text, nullable=False)
    full_code = db.Column(db.Text)
    language = db.Column(db.String(20), nullable=False)
    status = db.Column(db.String(20), nullable=False)
    execution_time = db.Column(db.Float)
    timestamp = db.Column(db.DateTime, default=lambda: datetime.now(BEIJING_TZ))


# ======================
# 题目讨论模型
# ======================
class Discussion(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    problem_id = db.Column(db.Integer, db.ForeignKey('problem.id'), nullable=False)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
    title = db.Column(db.String(200), nullable=False)
    content = db.Column(db.Text, nullable=False)
    timestamp = db.Column(db.DateTime, default=lambda: datetime.now(BEIJING_TZ))
    comments = db.relationship('Comment', backref='discussion', lazy=True, cascade="all, delete-orphan")


# ======================
# 讨论评论模型
# ======================
class Comment(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    discussion_id = db.Column(db.Integer, db.ForeignKey('discussion.id'), nullable=False)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
    content = db.Column(db.Text, nullable=False)
    timestamp = db.Column(db.DateTime, default=lambda: datetime.now(BEIJING_TZ))


# ======================
# 用户-已解决题目 关联表
# ======================
user_solved = db.Table('user_solved',
    db.Column('user_id', db.Integer, db.ForeignKey('user.id')),
    db.Column('problem_id', db.Integer, db.ForeignKey('problem.id'))
)